#ifndef ENTERA_CUH
#define ENTERA_CUH

//Incluyo la clase Random para la generación de números aleatorios en CUDA
#include "../utils/Random.cu"

/****************** Representacion entera ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionEntera();
void traerImprimirEntera(float* fitnessHost, float* fitnessDevice, int tamVectorFitnessFloat, int* poblacionHost, int* poblacionDevice, int tamVectorPoblacion, int iteracion);
void traerImprimirMejorIndividuoEntera(float* mejorFitnessIndividuoGPU, float* mejorFitnessIndividuoGPUDevice, int tamVectorFitnessMejoresIndividuosGPU, int* mejorIndividuoGPU, int* mejorIndividuoGPUDevice, int tamVectorMejoresIndividuosGPU, int iteracion);

/******************* Declaracion de Funciones Global del Device ********************/
__global__ void inicializarPoblacionEntera(int* poblacion, float* fitnessActualDevice, struct Random randomGPU, int cantCromosomasPoblacion, float* fitnessOrdenadoDevice, float* matrizTiemposDevice);
__global__ void mainKernelEntera(int* poblacionActualDevice, int* nuevaPoblacionDevice, float* fitnessActualDevice, float* nuevoFitnessDevice, int* poblacionActualAcambiarDevice, int* nuevaPoblacionAcambiarDevice, int* individuosAMigrarDevice, float* probabilidadRuletaDevice, float* fitnessTotalParaRuletaDevice, struct Random r, int * individuoAMigrarGPUaCPUdevice, float* fitnessOrdenadoDevice, int* vectorIndicesFitnessOrdenado, int iteracion, int* mejorIndividuoGPUDevice, float* mejorFitnessIndividuoGPUDevice, float* matrizTiemposDevice);
__global__ void obtenerMejoresIndividuosEntera(int* poblacion, float* fitness, int* mejorIndividuoDevice, float* mejorFitnessIndividuoGPUDevice);

/******************* Declaracion de Funciones internas del Device *****************/

__device__ int obtenerMejorIndividuoEntera(float* vectorFitness);
__device__ void obtenerPeorIndividuoEntera(float* vectorFitness, int indices[2]);

__global__ void migracionRepresentacionEntera(int* poblacionActualDevice, float* fitnessActualDevice, int* individuosAMigrarDevice, struct Random randomGPU, int* individuoAMigrarCPUaGPUdevice, float* matrizTiemposDevice);
__global__ void obtenerMejoresIndividuosEntera(int* poblacion, float* fitness, int* mejorIndividuoDevice, float* mejorFitnessIndividuoGPUDevice);
__device__ void individuosAMigrarRepresentacionEntera(float* nuevoFitnessDevice, int* nuevaPoblacionDevice, int* individuosAMigrarDevice, int * individuoAMigrarGPUaCPUdevice);

__device__ void asignarProbabilidadRuletaEntera(float* fitnessActualDevice, float* probabilidadRuletaEntera, float* fitnessTotalParaRuletaDevice, struct Random randomGPU);

__device__ int seleccionEntera(float* vectorFitness, float* probabilidadRuletaDevice, struct Random randomGPU, int ejecutarFuncion, int* vectorIndicesFitnessOrdenado);
__device__ int seleccionPorTorneoEntera(float* vectorFitness, struct Random randomGPU);
__device__ int seleccionPorRangoEntera(int* vectorIndicesFitnessOrdenado, struct Random randomGPU);
__device__ int seleccionRuedaRuletaEntera(float* probabilidadRuletaDevice, struct Random randomGPU);

__device__ void cruzamientoRepresentacionEntera(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void cruzamientoCromosoma1Punto(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosoma2Puntos(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);
__device__ void cruzamientoCromosomaUniforme(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU);

__device__ void mutacionEntera(int* poblacion, float probabilidad, struct Random randomGPU, int ejecutarFuncion);
__device__ void mutacionReajusteAleatorio(int* poblacion, float probabilidad, struct Random randomGPU);
__device__ void mutacionPorDeslizamiento(int* poblacion, float probabilidad, struct Random randomGPU);

__device__ void asignarFitnessEntera(int* poblacion, float* vectorFitness, float* fitnessOrdenadoDevice, float* matrizTiemposDevice);

__device__ void reemplazoEntera(int * poblacionActualDevice, int * nuevaPoblacionDevice, int * poblacionActualAcambiar, int * nuevaPoblacionAcambiar, float* fitnessActualDevice, float* nuevoFitnessDevice, int ejecutarFuncion);
__device__ void reemplazoElitistaEntera(int* poblacionActual, int* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float* fitnessActual, float* nuevoFitness);

#endif
